package com.wangshili.common.config;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

/**
 * 安全框架配置类
 * @author wangshili
 *
 */
@Configuration
public class ShiroConfig {
	
	/**
	 * 安全工厂
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean getSecurityFilterAutoConfiguration(
			@Autowired SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFct= new ShiroFilterFactoryBean();
		//1.设置安全管理器，使用自动注入我们写好的
		shiroFct.setSecurityManager(securityManager);
		/**
		 * 2.添加Shiro内置过滤器，实现路径访问权限控制
		 * 常用的过滤器：
		 * 	anon:无需登录可以访问
		 * 	authc:必须登录才可以访问
		 * 	user:登录才可以访问胆如果使用rememberme功能，可以直接访问
		 * 	perms:该资源必须有资源权限才可以访问
		 * 	role:该资源必须要有角色权限才可以访问
		 */
		//使用linkedHashMap保证插入的有序
		Map<String, String> map = new LinkedHashMap<>();
		//因为shiro是按照从上到下的关系配置，需要先将允许的路径放到前面
		map.put("/doLogin", "anon");//登录校验
		//放行静态资源
		map.put("/bower_components/**","anon");
        map.put("/build/**","anon");
        map.put("/dist/**","anon");
        map.put("/plugins/**","anon");
        map.put("/doLogout","logout");//注销 
        //其他路径均禁止访问
        map.put("/**", "user");//需要登录才能进，如果有rememberme功能，可以直接访问
		/**
		 * 如果授权失败会默认跳转到一个页面，这里我们指定下
		 */
//        shiroFct.setUnauthorizedUrl("/");
		/**
		 * 设置拦截成功跳转的界面，默认是login.jsp
		 */
        shiroFct.setLoginUrl("/login");//去登陆页
        shiroFct.setFilterChainDefinitionMap(map);
		return shiroFct;
	}
	/**
	 * 配置安全管理器，使用子类DefaultWebSecurityManager
	 * @param realm 领域对象
	 * @return
	 */
	@Bean
	public SecurityManager securityManager(Realm realm,CacheManager cacheManager,
			RememberMeManager rememberMeManager,SessionManager sessionManager) {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(realm);
		manager.setCacheManager(cacheManager);
		manager.setRememberMeManager(rememberMeManager);
		manager.setSessionManager(sessionManager);
		return manager;
	}
	
	/**
	 * 使用认证器必须配置这个bean
	 * 配置advisor对象,shiro框架底层会通过此对象的matchs方法返回值(类似切入点)决定是否创建代理对象,进行权限控制。
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor getAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor adv = new AuthorizationAttributeSourceAdvisor();
		adv.setSecurityManager(securityManager);
		return adv;
	}
	
	/**
	 * 使用shiro缓存，缓存认证器的内容，避免每次认证都需要查数据库，也可以使用第三方插件比如redis
	 * @return
	 */
	@Bean
	public CacheManager shiroCacheManager() {
		return new MemoryConstrainedCacheManager();
	}
	
	/**
	 * 配置记住我功能,cookie
	 */
	@Bean
	public RememberMeManager getRememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();//cookie管理器
		SimpleCookie simpleCookie = new SimpleCookie("rememberMe");//创建一个cookie
		simpleCookie.setMaxAge(3600*24*7);//7天存活期
		cookieRememberMeManager.setCookie(simpleCookie);//设置cookie
		return cookieRememberMeManager;
	}
	/**
	 * 配置session存活时间
	 */
	@Bean
	public SessionManager getSessionManager() {
		DefaultWebSessionManager sManager = new DefaultWebSessionManager();
		sManager.setGlobalSessionTimeout(3600*24*7);//设置session存活时间
		return sManager;
	}
	/**
	 * 配合thymeleaf使用
	 * @return
	 */
	@Bean
	public ShiroDialect getShiroDialect() {
		return new ShiroDialect();
	}
}
